﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ArgusPCLib.Collections.Generic
{
	public enum ChangeTypes
	{
		Added,
		Removed,
		Exchanged,
		Inserted
	}

	public class ItemChangedEventArgs<T> : EventArgs
	{
		public T OldValue { get; private set; }
		public T NewValue { get; private set; }
		public ChangeTypes ChangeType{get;private set;}
		public int ItemIndex{get;private set;}

		public ItemChangedEventArgs(T oldValue, T newValue, ChangeTypes changeType, int itemIndex)
			:base()
		{
			this.OldValue = oldValue;
			this.NewValue = newValue;
			this.ChangeType = changeType;
			this.ItemIndex = itemIndex;
		}
	}

	public delegate void ItemChangedEventHandler<T>(object sender, ItemChangedEventArgs<T> e);

	public class ItemCollection<T> : IList<T>
	{
		List<T> _items;

		public event ItemChangedEventHandler<T> ItemChanged;

		public ItemCollection() { this._items = new List<T>(); }
		public ItemCollection(IEnumerable<T> items) { this._items = new List<T>(items); }
		public ItemCollection(int capacity) { this._items = new List<T>(capacity); }

		bool ICollection<T>.IsReadOnly { get { return false; } }
		public int Count { get { return this._items.Count; } }

		protected virtual void OnItemChanged(ItemChangedEventArgs<T> e)
		{
			if (this.ItemChanged != null)
				this.ItemChanged(this, e);
		}

		public T this[int index]
		{
			get { return this._items[index]; }
			set
			{
				ItemChangedEventArgs<T> e = new ItemChangedEventArgs<T>(this._items[index], value, ChangeTypes.Exchanged, index);
				this._items[index] = value;
				this.OnItemChanged(e);
			}
		}

		public void Add(T item)
		{
			ItemChangedEventArgs<T> e = new ItemChangedEventArgs<T>(default(T), item, ChangeTypes.Added, this._items.Count);
			this._items.Add(item);
			this.OnItemChanged(e);
		}

		public void RemoveAt(int index)
		{
			ItemChangedEventArgs<T> e = new ItemChangedEventArgs<T>(this._items[index], default(T), ChangeTypes.Removed, index);
			this._items.RemoveAt(index);
			this.OnItemChanged(e);
		}

		public bool Remove(T item)
		{
			int index = this._items.IndexOf(item);
			if (index < 0)
				return false;
			this.RemoveAt(index);
			return true;
		}

		public void Insert(int index, T item)
		{
			ItemChangedEventArgs<T> e = new ItemChangedEventArgs<T>(default(T), item, ChangeTypes.Inserted, index);
			this._items.Insert(index, item);
			this.OnItemChanged(e);
		}

		public int IndexOf(T item) { return this._items.IndexOf(item); }
		public void CopyTo(T[] array, int arrayIndex) { this._items.CopyTo(array, arrayIndex); }
		public void CopyTo(T[] array) { this._items.CopyTo(array); }

		public T[] ToArray()
		{
			T[] array = new T[this._items.Count];
			this._items.CopyTo(array);
			return array;
		}

		public bool Contains(T item) { return this._items.Contains(item); }

		public void Clear()
		{
			while (this._items.Count > 0)
				this.RemoveAt(0);
		}

		public IEnumerator<T> GetEnumerator() { return new Enumerator(this); }
		IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); }

		class Enumerator : IEnumerator<T>
		{
			int _index;
			ItemCollection<T> _collection;

			public Enumerator(ItemCollection<T> collection)
			{
				this._collection = collection;
				this.Reset();
			}

			public void Reset() { this._index = -1; }

			public T Current { get { return this._collection[this._index]; } }
			object IEnumerator.Current { get { return this.Current; } }

			public bool MoveNext()
			{
				this._index++;
				return this._index < this._collection.Count;
			}

			void IDisposable.Dispose() { this._collection = null; }
		}
	}
}
